package vn.gq.tym.utils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.zip.GZIPInputStream;

import org.apache.http.HttpStatus;
import org.json.JSONException;
import org.json.JSONTokener;

import vn.gq.tym.comictemplate.BuildConfig;
import vn.gq.tym.comictemplate.Configuation;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import android.util.Log;

public class Client extends AsyncTask<String, Integer, Object> {
	
	private long expired = 864000;			// 10 days
	private Context context;
	private IClientListener mListener;
	private int errorCode = 0;
	private DataType dataType = DataType.NORMAL;
	private HttpURLConnection httpURLConnection = null;
	private File mHttpCacheDir;
	private NetworkOption mNetworkOption = NetworkOption.OPTION_USE_NETWORK;
	
	
	public Client(Context context) {
		this.context = context;
		mHttpCacheDir = AndroidUtils.getDiskCacheDir(context, null);
		initHttpDiskCache();
	}
	
	public void setOutputDataType(DataType type) {
		dataType = type;
	}
	
	public void setNetworkOption(NetworkOption option) {
		mNetworkOption = option;
	}
	
	public void executeAndListener(String url, IClientListener listener) {
		mListener = listener;
		execute(url);
	}
	
	public void setCacheTime(long value) {
		expired = value;
	}
	
	@Override
	protected Object doInBackground(String... params) {
		disableConnectionReuseIfNecessary();
		InputStream is;
		String url = params[0];
		if (BuildConfig.DEBUG) {
			Log.e(getClass().getSimpleName(), "---load url: "+String.valueOf(url));
		}
		try {
			if (url.startsWith("asset://")) {
				url = url.substring("asset://".length());
				if (url.startsWith("gzip:")) {
					url = url.substring("gzip:".length());
					switch(dataType) {
						case NORMAL:
							dataType = DataType.GZIP; break;
						case JSON:
							dataType = DataType.GZIP_JSON; break;
						case CIPHER_JSON:
							dataType = DataType.GZIP_CIPHER_JSON; break;
						default:
							break;
					}
				}
				is = context.getAssets().open(url);
			} else {
				String key = Utils.md5(url);
				if (null==(is=ClientIO.getCache(mHttpCacheDir, key, mNetworkOption == NetworkOption.OPTION_USE_NETWORK))) {
				
					httpURLConnection = (HttpURLConnection) new URL(url).openConnection();
					httpURLConnection.setRequestMethod("GET");
					int code = httpURLConnection.getResponseCode();
					if (code == HttpStatus.SC_OK) {
						String encoding = httpURLConnection.getHeaderField("Content-Encoding");
						if (encoding != null) {
							if (encoding.contains("gzip")) {
								switch(dataType) {
									case NORMAL:
										dataType = DataType.GZIP; break;
									case JSON:
										dataType = DataType.GZIP_JSON; break;
									case CIPHER_JSON:
										dataType = DataType.GZIP_CIPHER_JSON; break;
									default:
										break;
								}
							}
						}
						is = ClientIO.cacheToSdcard(mHttpCacheDir, key, httpURLConnection.getInputStream(), System.currentTimeMillis() + expired);
					} else {
						errorCode = code;
						return null;
					}
				}
			}
			switch(dataType) {
				case GZIP:
				case GZIP_JSON:
				case GZIP_CIPHER_JSON:
					is = new GZIPInputStream(is);
					break;
				default:
					break;
			}
			String result = ClientIO.convertStreamToString(is, null);
			
			if (dataType == DataType.CIPHER || 
					dataType == DataType.CIPHER_JSON ||
					dataType == DataType.GZIP_CIPHER_JSON) {
				try {
					String plainText = new AESCipher(new String(Base64.decode(Configuation.CIPHER_KEY, Base64.URL_SAFE))).decrypt(result);
					result = plainText;
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			switch(dataType) {
				case CIPHER_JSON:
				case GZIP_JSON:
				case GZIP_CIPHER_JSON:
				case JSON:
					Object j = new JSONTokener(result).nextValue();
					return j;
				default: break;
			}
			return result;
		} catch(IOException e) {
			errorCode = 1;
			e.printStackTrace();
		} catch (JSONException e) {
			errorCode = 2;
			e.printStackTrace();
		} finally {
			if (httpURLConnection != null) {
				httpURLConnection.disconnect();
			}
		}
		return null;
	}
	
	@Override
	protected void onPostExecute(Object result) {
		super.onPostExecute(result);
		if (mListener != null) {
			mListener.onDone(errorCode, result);
		}
	}
	
	private void initHttpDiskCache() {
        if (!mHttpCacheDir.exists()) {
            mHttpCacheDir.mkdirs();
        }
    }
	
	public static void disableConnectionReuseIfNecessary() {
        // HTTP connection reuse which was buggy pre-froyo
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {
            System.setProperty("http.keepAlive", "false");
        }
    }
}
